/**
 * Tree combobox
 *
 * @author liuhz
 */
CQCIS.form.TreeComboBox = Ext.extend(Ext.form.TriggerField, {
    /**
     * @cfg dwrCall
     * @cfg root
     * @cfg rootVisible Boolean
     * @cfg rootId Root id
     * @cfg rootText Root desc
     */
    readOnly: true,
    hiddenName: undefined,
    displayValue: undefined,
    displayField: 'text',
    valueField: 'id',
    listAlign: 'tl-bl?',
    shadow: 'sides',
    listClass: '',
    rootVisible: false,
    rootText: '根节点',
    rootId: '-1',
    lazyInit: true,
    minListWidth: 70,
    maxHeight: 300,
    width: 140,
    listWidth: 140,
    treeListeners: undefined,
    handleHeight: 8,
    resizable: true,
    
    initComponent: function(){
        CQCIS.form.TreeComboBox.superclass.initComponent.call(this);
        
        this.addEvents({
            'load': true,
            'select': true,
            'expand': true,
            'collapse': true,
            'beforeselect': true,
            'beforeload': true
        });
    },
    
    setValue: function(node){
        var text, value;
        if (typeof node == 'object') {
            text = node.text;
            value = node.id;
        } else if (node && node.length > 0) {
            if (!this.list) {
                this.initList();
            }
            var valueField = this.valueField;
            var displayField = this.displayField;
            
            var findRoot = function(nd, id){
                var child = nd.findChild('id', id), cs = nd.childNodes;
                if (child) {
                    return child;
                } else if (cs && cs.length > 0) {
                    for (var i = 0; i < cs.length; i++) {
                        var c = findNode(cs[i].attributes, id);
                        if (c) {
                            return {
                                id: c[valueField],
                                text: c[displayField]
                            };
                        }
                    }
                }
                return null;
            };
            var findNode = function(attr, id){
                var cs = attr.children;
                if (attr[valueField] == id) {
                    return attr;
                } else if (cs && cs.length > 0) {
                    for (var i = 0; i < cs.length; i++) {
                        var c = findNode(cs[i], id);
                        if (c) {
                            return c;
                        }
                    }
                }
                return null;
            };
            
            var n = findRoot(this.tree.root, node);
            if (n) {
                text = n.text;
                value = n.id;
            } else {
                value = node;
            }
        }
        if (this.hiddenField) {
            this.hiddenField.value = value;
        }
        CQCIS.form.TreeComboBox.superclass.setValue.call(this, text);
        this.value = value;
        this.displayValue = text;
    },
    
    getValue: function(){
        if (this.valueField) {
            return typeof this.value != 'undefined' ? this.value : '';
        } else {
            return CQCIS.form.TreeComboBox.superclass.getValue.call(this);
        }
    },
    getNode: function(){
        return this.tree.getSelectionModel().getSelectedNode();
    },
    
    onSelect: function(node){
        if (this.fireEvent('beforeselect', node, this) !== false) {
            this.setValue(node);
            this.collapse();
            this.fireEvent('select', this, node);
        }
    },
    onRender: function(ct, position){
        var value = this.value;
        CQCIS.form.TreeComboBox.superclass.onRender.call(this, ct, position);
        this.value = value;
        if (this.hiddenName) {
            this.hiddenField = this.el.insertSibling({
                tag: 'input',
                type: 'hidden',
                name: this.hiddenName,
                id: (this.hiddenId || this.hiddenName)
            }, 'before', true);
            this.hiddenField.value = this.hiddenValue !== undefined ? this.hiddenValue : this.value !== undefined ? this.value : '';
            this.el.dom.removeAttribute('name');
        }
        if (Ext.isGecko) {
            this.el.dom.setAttribute('autocomplete', 'off');
        }
        
        if (!this.lazyInit) {
            this.initList();
        } else {
            this.on('focus', this.initList, this, {
                single: true
            });
        }
    },
    // private
    createTree: function(el){
        if (!this.root) {
            this.root = new Ext.tree.AsyncTreeNode({
                expandable: true,
                expanded: true,
                text: this.rootText,
                id: this.rootId
            });
        }
        if (!this.loader && this.dwrCall) {
            this.loader = new CQCIS.tree.DWRTreeLoader({
                dwrCall: this.dwrCall,
                listeners: this.loaderListeners,
                nodeMeta: {
                    id: this.valueField,
                    text: this.displayField
                }
            });
        }
        this.loader.on('load', this.onLoad.createDelegate(this));
        this.loader.on('beforeload', function(o, node){
            if (node.isRoot) {
                this.onBeforeLoad();
            }
        }, this);
        
        this.root.on('load', function(){
            this.fireEvent('load', this);
        }, this);
        
        var tree = new Ext.tree.TreePanel({
            border: false,
            animate: true,
            enableDD: false,
            containerScroll: true,
            rootVisible: this.rootVisible,
            loader: this.loader,
            root: this.root,
            listeners: this.treeListeners
        });
        tree.render(el);
        return tree;
    },
    
    reload: function(id, text){
        if (id) {
            this.rootId = id;
        }
        if (text) {
            this.rootText = text;
        }
        if (this.tree) {
            this.tree.root.id = this.rootId;
            this.tree.root.reload();
        }
    },
    
    // private
    initList: function(){
        if (!this.list) {
            var cls = 'x-combo-list';
            this.list = new Ext.Layer({
                shadow: this.shadow,
                cls:[cls,this.listClass] .join(' '),
                constrain: false
            });
            var lw = this.listWidth ||
            Math.max(this.wrap.getWidth(), this.minListWidth);
            this.list.setWidth(lw);
            this.list.swallowEvent('mousewheel');
            this.assetHeight = 0;
            this.innerList = this.list.createChild({
                cls: cls + '-inner'
            });
            this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
            
            var tree = this.createTree(this.innerList);
            
            var treeField = this;
            tree.on('click', function(node, e){
                e.stopEvent();
                treeField.onSelect(node);
            });
            tree.on('expandnode', this.restrictHeight, this);
            tree.on('collapsenode', this.restrictHeight, this);
            
            this.tree = tree;
            
            if (this.value && this.displayValue) {
                var node = {
                    id: this.value ? this.value : '',
                    text: this.displayValue ? this.displayValue : ''
                };
                this.setValue(node);
            } else if (this.value) {
                this.setValue(this.value);
            }
            
            if (this.resizable) {
                this.resizer = new Ext.Resizable(this.list, {
                    pinned: true,
                    handles: 'e'
                });
                this.resizer.on('resize', function(r, w, h){
                    this.listWidth = w;
                    this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
                }, this);
                this.list.setStyle('padding-right', '5px');
            }
        }
        this.onBeforeLoad();
    },
    onDestroy: function(){
        if (this.tree) {
            this.tree.onDestroy();
        }
        if (this.list) {
            this.list.destroy();
        }
        CQCIS.form.TreeComboBox.superclass.onDestroy.call(this);
    },
    isExpanded: function(){
        return this.list && this.list.isVisible();
    },
    collapse: function(){
        if (!this.isExpanded()) {
            return;
        }
        this.list.hide();
        Ext.get(document).un('mousedown', this.collapseIf, this);
        Ext.get(document).un('mousewheel', this.collapseIf, this);
        this.fireEvent('collapse', this);
    },
    collapseIf: function(e){
        if (!e.within(this.wrap) && !e.within(this.list)) {
            this.collapse();
        }
    },
    expand: function(){
        if (this.isExpanded()) {
            return;
        }
        this.list.alignTo(this.el, this.listAlign);
        this.list.show();
        Ext.get(document).on('mousedown', this.collapseIf, this);
        Ext.get(document).on('mousewheel', this.collapseIf, this);
        this.fireEvent('expand', this);
    },
    onTriggerClick: function(){
        if (this.disabled) {
            return;
        }
        if (this.isExpanded()) {
            this.collapse();
        } else {
            this.onFocus();
            this.expand();
            this.restrictHeight();
        }
        this.el.focus();
    },
    onBeforeLoad: function(){
        if (!this.hasFocus) {
            return;
        }
        if (!this.list.child('div.loading-indicator')) {
            this.list.insertFirst({
                tag: 'div',
                cls: 'x-combo-list-inner',
                html: '<div class="loading-indicator">读取中...</div>'
            });
        } else {
            this.list.child('div.loading-indicator').setStyle('display', 'block');
        }
    },
    onLoad: function(){
        if (!this.hasFocus) {
            return;
        }
        if (this.list.child('div.loading-indicator')) {
            this.list.child('div.loading-indicator').setStyle('display', 'none');
            this.restrictHeight();
        }
    },
    // private
    restrictHeight: function(){
        this.innerList.dom.style.height = '';
        var inner = this.innerList.dom;
        var pad = this.list.getFrameWidth('tb') + this.assetHeight;
        var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
        var ha = this.getPosition()[1] - Ext.getBody().getScroll().top;
        var hb = Ext.lib.Dom.getViewHeight() - ha - this.getSize().height;
        var space = Math.max(ha, hb, this.minHeight || 0) - this.list.shadowOffset - pad - 5;
        h = Math.min(h, space, this.maxHeight);
        
        this.innerList.setHeight(h);
        this.list.beginUpdate();
        this.list.setHeight(h + pad);
        this.list.alignTo(this.wrap, this.listAlign);
        this.list.endUpdate();
    }
});
Ext.reg('treecombo', CQCIS.form.TreeComboBox);
